home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 November: Tool Chest / Dev.CD Nov 98 TC.toast / Sample Code / Networking / OTPingSample / OTPingSample.c next >
Encoding:
C/C++ Source or Header  |  1996-06-28  |  6.4 KB  |  279 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:                OTPingSample.c
  3.  
  4.     Contains:        A trivial ping implementation.
  5.  
  6.     Written by:    Quinn "The Eskimo!"
  7.  
  8.     Copyright:    © 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.     You may incorporate this sample code into your applications without
  13.     restriction, though the sample code has been provided "AS IS" and the
  14.     responsibility for its operation is 100% yours.  However, what you are
  15.     not permitted to do is to redistribute the source as "DSC Sample Code"
  16.     after having made changes. If you're going to re-distribute the source,
  17.     we require that you make it clear in the source that the code was
  18.     descended from Apple Sample Code, but that you've made changes.
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <OpenTransport.h>
  23. #include <OpenTptInternet.h>
  24.  
  25. /////////////////////////////////////////////////////////////////////
  26.  
  27. static UInt16 ChecksumBuffer(UInt16* buf, size_t len)
  28. {
  29.     // This checksum implementation requires the buffer to be an even number of bytes long.
  30.     UInt32 sum;
  31.     size_t nwords;
  32.     
  33.     nwords = len / 2;
  34.     sum = 0;
  35.     while (nwords > 0) {
  36.         sum += *buf;
  37.         buf++;
  38.         nwords -= 1;
  39.     }
  40.     sum = (sum >> 16 ) + (sum & 0xffff);
  41.     sum += (sum >> 16);
  42.  
  43.     return ~sum;
  44. }
  45.  
  46. /////////////////////////////////////////////////////////////////////
  47.  
  48. static OSStatus CreateAndConfigICMP(EndpointRef *ep)
  49. {
  50.     OSStatus err;
  51.     
  52.     *ep = OTOpenEndpoint(OTCreateConfiguration(kRawIPName), 0, nil, &err);
  53.     
  54.     if (err == noErr) {
  55.     err = OTBind(*ep, nil, nil);
  56.     
  57.         // no others options to negotiate at this stage
  58.         
  59.         // You might think we need to negotiate the XTI_GENERIC/XTI_PROTOTYPE
  60.         // option to request ICMP packets (ie protocol 2).  This is not
  61.         //  necessary because rawip endpoints default to that protocol.
  62.     }
  63.     
  64.     return (err);
  65. }
  66.  
  67. /////////////////////////////////////////////////////////////////////
  68.  
  69. static OSStatus LookupName(InetSvcRef inet_services, char *host_name, InetHost *host_addr)
  70. {
  71.     OSStatus err;
  72.     InetHostInfo response;
  73.     
  74.     memset(&response, 0, sizeof(response));
  75.     
  76.     err = OTInetStringToAddress(inet_services, host_name, &response);
  77.     
  78.     if (err == noErr) {
  79.         *host_addr = response.addrs[0];
  80.     }
  81.  
  82.     return (err);
  83. }
  84.  
  85. /////////////////////////////////////////////////////////////////////
  86.  
  87. enum {
  88.     kOurMagic = 'Quin'
  89. };
  90.  
  91. struct PingPacket {
  92.     UInt8   pType;
  93.     UInt8   pCode;
  94.     UInt16  pChecksum;
  95.     UInt16  pID;
  96.     UInt16  pSeqNum;
  97.     OSType    pMagic;
  98. };
  99. typedef struct PingPacket PingPacket, *PingPacketPtr;
  100.  
  101. /////////////////////////////////////////////////////////////////////
  102.  
  103. static OSStatus SendICMP(EndpointRef ep, InetHost dest, UInt16 seq_number)
  104. {
  105.     OSStatus err;
  106.     InetAddress dest_addr;
  107.     TUnitData udata;
  108.     PingPacket ping_data;
  109.  
  110.     OTInitInetAddress(&dest_addr, 0, dest);        
  111.  
  112.     ping_data.pType = 8;
  113.     ping_data.pCode = 0;
  114.     ping_data.pChecksum = 0;        // dummy checksum of 0 for purposes of checksum calculation
  115.     ping_data.pID = 666;
  116.     ping_data.pSeqNum = seq_number;
  117.     ping_data.pMagic = kOurMagic;
  118.  
  119.     ping_data.pChecksum = ChecksumBuffer((UInt16 *) &ping_data, sizeof(ping_data));
  120.  
  121.     udata.addr.len = sizeof(dest_addr);
  122.     udata.addr.buf = (unsigned char *) &dest_addr;
  123.     
  124.     udata.opt.len = 0;
  125.     udata.opt.buf = nil;
  126.     
  127.     udata.udata.len = sizeof(ping_data);
  128.     udata.udata.buf = (UInt8 *) &ping_data;
  129.  
  130.     err = OTSndUData(ep, &udata);
  131.  
  132.     return (err);
  133. }
  134.  
  135. /////////////////////////////////////////////////////////////////////
  136.  
  137. // we use this buffer to hold incoming ICMP packets
  138.  
  139. static UInt8 icmp_data[5000];
  140.  
  141. /////////////////////////////////////////////////////////////////////
  142.  
  143. static OSStatus WaitAndPrintICMPs(EndpointRef ep, UInt16 seq_number, Boolean *got_response)
  144. {
  145.     TUnitData udata;
  146.     long start_time;
  147.     OSStatus err;
  148.     InetAddress src_addr;
  149.     PingPacketPtr ping_data_ptr;
  150.     
  151.     *got_response = false;
  152.  
  153.     start_time = TickCount();
  154.     
  155.     // Wait for 5 seconds and print out any ICMP packets we get back.
  156.     
  157.     do {
  158.  
  159.         // Set up the received...
  160.         
  161.         udata.addr.buf = (UInt8*) &src_addr;
  162.         udata.addr.maxlen = sizeof(struct InetAddress);
  163.         udata.opt.buf = nil;
  164.         udata.opt.maxlen = 0;
  165.         udata.udata.buf = icmp_data;
  166.         udata.udata.maxlen = sizeof(icmp_data);
  167.         
  168.         // Look for a packet...
  169.         
  170.         err = OTRcvUData(ep, &udata, nil);
  171.         if (err == noErr) {
  172.             // Print out salient information from the packet...
  173.             printf("•••Got ICMP!•••\n");
  174.             
  175.             printf("ICMP from = %d.%d.%d.%d\n", icmp_data[12], icmp_data[13], icmp_data[14], icmp_data[15]);
  176.  
  177.             ping_data_ptr = (PingPacketPtr) &icmp_data[20];
  178.             
  179.             printf("ICMP type = %d\n", ping_data_ptr->pType);
  180.             printf("ICMP code = %d\n", ping_data_ptr->pCode);
  181.             
  182.             if (ping_data_ptr->pType == 0
  183.                             && ping_data_ptr->pID == 666 
  184.                             && ping_data_ptr->pSeqNum == seq_number 
  185.                             && ping_data_ptr->pMagic == kOurMagic) {
  186.                 *got_response = true;
  187.             }
  188.             
  189.             fflush(stdout);
  190.         } else if (err == kOTNoDataErr) {
  191.             err = noErr;
  192.         }
  193.     } while (err == noErr && TickCount() < start_time + 5 * 60);
  194.  
  195.     return (err);
  196. }
  197.  
  198. /////////////////////////////////////////////////////////////////////
  199.  
  200. static OSStatus DoPing(InetHost dest)
  201. {
  202.     OSStatus err;
  203.     EndpointRef icmp_ep = nil;
  204.     UInt16 seq_number;
  205.     UInt16 lost;
  206.     Boolean got_response;
  207.     
  208.     // Create the endpoint and negotiate the options...
  209.     err = CreateAndConfigICMP(&icmp_ep);
  210.     
  211.     // Do the main ping loop...
  212.     
  213.     seq_number = 0;
  214.     lost = 0;
  215.     do {
  216.         printf("\nSending ping...\n");
  217.         err = SendICMP(icmp_ep, dest, seq_number);
  218.         if (err == noErr) {
  219.             err = WaitAndPrintICMPs(icmp_ep, seq_number, &got_response);
  220.         }
  221.         if (err == noErr) {
  222.             if (!got_response) {
  223.                 lost += 1;
  224.             }
  225.             seq_number += 1;
  226.         }
  227.     } while (err == noErr && seq_number < 5);
  228.  
  229.     if (err == noErr) {
  230.         printf("Ping complete.  %d packets sent.  %d packets lost.  %d%% packet loss.\n", seq_number, lost, lost * 100 / seq_number);
  231.     }
  232.  
  233.     // clean up
  234.     if (icmp_ep != nil) {
  235.         (void) OTCloseProvider(icmp_ep);
  236.     }
  237.     return err;
  238. }
  239.  
  240. /////////////////////////////////////////////////////////////////////
  241.  
  242. void main(void) {
  243.     OSStatus err;
  244.     char host_name[256];
  245.     InetHost host_addr;
  246.     InetSvcRef inet_services = nil;
  247.     
  248.     printf("Hello Cruel World!\n");
  249.     
  250.     err = InitOpenTransport();
  251.     
  252.     if (err == noErr) {
  253.         inet_services = OTOpenInternetServices(kDefaultInternetServicesPath, 0, &err);
  254.         
  255.         if (err == noErr) {
  256.             printf("Enter name of host to ping:\n");
  257.             gets(host_name);
  258.             
  259.             err = LookupName(inet_services, host_name, &host_addr);
  260.         }
  261.         
  262.         if (err == noErr) {
  263.             err = DoPing(host_addr);
  264.         }
  265.  
  266.         if (inet_services != nil) {
  267.             OTCloseProvider(inet_services);
  268.         }
  269.     
  270.         CloseOpenTransport();
  271.     }
  272.     
  273.     if (err == noErr) {
  274.         printf("Success!\n");
  275.     } else {
  276.         printf("Failure!  Error = %d.\n", err);
  277.     }
  278.     printf("Done.  Press command-Q to Quit.\n");
  279. }